package com.qf.aop.aspect;

import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.qf.aop.config.Ip2regionUtil;
import com.qf.api.entity.SysOperationLogEntity;
import com.qf.api.entity.SysUserEntity;
import com.qf.core.enums.common.OperationStatusEnum;
import com.qf.core.enums.common.RequestMethodEnum;
import com.qf.core.response.ResponseResult;
import com.qf.core.utils.ServletUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;

import static org.springframework.util.StringUtils.truncate;

/**
 * @Author: sin
 * @Date: 2025/5/9 15:35
 * @Description:
 **/
@Slf4j
public class OperationLogModel extends SysOperationLogEntity {

    public static final int MAX_DATA_LENGTH = 512;

    private final HttpServletRequest request = ServletUtils.getRequest();

    public void fillOperatorInfo(String username, Long id) {
        // 获取当前的用户
        String ip = Ip2regionUtil.getIpAddr(request);
        String ipAddr = Ip2regionUtil.getAddr(ip);
        this.setOperatorIp(ip);
        this.setOperatorLocation(ipAddr);
        this.setUsername(username);
        this.setUserId(id);
    }


    public void fillRequestInfo(final JoinPoint joinPoint, ApiOperationLog accessLog, Object jsonResult) {
        this.setRequestUrl(request.getRequestURI());
        // 设置方法名称
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        String methodFormat = StrUtil.format("{}.{}()", className, methodName);
        this.setCalledMethod(methodFormat);
        // 设置请求方式
        RequestMethodEnum requestMethodEnum = EnumUtil.fromString(RequestMethodEnum.class,
                request.getMethod());
        this.setRequestMethod(requestMethodEnum != null ? requestMethodEnum.getValue() : RequestMethodEnum.UNKNOWN.getValue());

        // 是否需要保存request，参数和值
        if (accessLog.isSaveRequestData()) {
            // 获取参数的信息，传入到数据库中。
            recordRequestData(joinPoint);
        }
        // 是否需要保存response，参数和值
        if (accessLog.isSaveResponseData() && jsonResult != null) {
            if (jsonResult instanceof ResponseResult<?>) {
                this.setOperationResult(truncate(JSON.toJSONString(jsonResult)));
            } else {
                this.setOperationResult("非自定义封装响应，结果暂不保存");
            }
        }
    }

    public void fillAccessLogInfo(JoinPoint joinPoint, ApiOperationLog log) {
        // 设置action动作
        this.setBusinessType(log.businessType().ordinal());
        Class<?> clazz = joinPoint.getTarget().getClass();
        // 获取类上的 title
        String moduleName = "未定义模块";
        ApiOperationLogTitle classLog = clazz.getAnnotation(ApiOperationLogTitle.class);
        if (classLog != null && !StringUtils.isBlank(classLog.value())) {
            moduleName = classLog.value();
        }
        this.setRequestModule(moduleName);
        this.setRequestDesc(log.desc());
        // 设置操作人类别
        this.setOperatorType(log.operatorType().ordinal());
    }

    public void fillStatus(Exception e) {
        if (e != null) {
            this.setStatus(OperationStatusEnum.FAIL.getValue());
            this.setErrorStack(StrUtil.sub(e.getMessage(), 0, MAX_DATA_LENGTH));
        } else {
            this.setStatus(OperationStatusEnum.SUCCESS.getValue());
        }
    }

    /**
     * 获取请求的参数，放到log中
     *
     * @param joinPoint 方法切面
     */
    private void recordRequestData(JoinPoint joinPoint) {
        try {
            String paramJson = AopParamResolver.resolveMethodParamsToJson(joinPoint);
            if (StrUtil.isNotBlank(paramJson)) {
                this.setOperationParam(paramJson);
            }
        } catch (Exception e) {
            log.warn("记录请求参数失败", e);
        }
    }
}